/**
 *All Winner Tech, All Right Reserved. 2014-2015 Copyright (c)
 *
 *File name   :de_rtmx.c
 *
 *Description :display engine 2.0 realtime mixer
 *             processing base functions implement
 *
 *History     :2014/02/08  iptang  v0.1  Initial version
 *
*/

#include "de_rtmx.h"
#include "de_rtmx_type.h"
#include "de_scaler.h"

static struct __rtmx_reg_t de200_rtmx[DE_NUM];

static struct de_reg_blocks glb_ctl_block[DE_NUM];

static struct de_reg_blocks
	vi_attr_block[DE_NUM][VI_CHN_NUM][LAYER_MAX_NUM_PER_CHN];
static struct de_reg_blocks vi_fc_block[DE_NUM][VI_CHN_NUM];
static struct de_reg_blocks vi_haddr_block[DE_NUM][VI_CHN_NUM];
static struct de_reg_blocks vi_size_block[DE_NUM][VI_CHN_NUM];

static struct de_reg_blocks
	ui_attr_block[DE_NUM][CHN_NUM - VI_CHN_NUM][LAYER_MAX_NUM_PER_CHN];
static struct de_reg_blocks ui_haddr_block[DE_NUM][CHN_NUM - VI_CHN_NUM];
static struct de_reg_blocks ui_size_block[DE_NUM][CHN_NUM - VI_CHN_NUM];

static struct de_reg_blocks bld_attr_block[DE_NUM];
static struct de_reg_blocks bld_ctl_block[DE_NUM];
static struct de_reg_blocks bld_ck_block[DE_NUM];
static struct de_reg_blocks bld_out_block[DE_NUM];
/* static uintptr_t de_base = 0; */
static uintptr_t de_base;

int de_rtmx_update_regs(unsigned int sel)
{
	int i, j, ui_chno, vi_chno, layno;

	vi_chno = de_feat_get_num_vi_chns(sel);
	ui_chno = de_feat_get_num_ui_chns(sel);
	layno = LAYER_MAX_NUM_PER_CHN;

	if (glb_ctl_block[sel].dirty == 0x1) {
		memcpy((void *)glb_ctl_block[sel].off, glb_ctl_block[sel].val,
		       glb_ctl_block[sel].size);
		glb_ctl_block[sel].dirty = 0;
	}

	for (j = 0; j < vi_chno; j++) {
		for (i = 0; i < layno; i++) {
			if (vi_attr_block[sel][j][i].dirty == 0x1) {
				memcpy((void *)vi_attr_block[sel][j][i].off,
				       vi_attr_block[sel][j][i].val,
				       vi_attr_block[sel][j][i].size);
				vi_attr_block[sel][j][i].dirty = 0;
			}
		}

		if (vi_fc_block[sel][j].dirty == 0x1) {
			memcpy((void *)vi_fc_block[sel][j].off,
			       vi_fc_block[sel][j].val,
			       vi_fc_block[sel][j].size);
			vi_fc_block[sel][j].dirty = 0;
		}

		if (vi_haddr_block[sel][j].dirty == 0x1) {
			memcpy((void *)vi_haddr_block[sel][j].off,
			       vi_haddr_block[sel][j].val,
			       vi_haddr_block[sel][j].size);
			vi_haddr_block[sel][j].dirty = 0;
		}

		if (vi_size_block[sel][j].dirty == 0x1) {
			memcpy((void *)vi_size_block[sel][j].off,
			       vi_size_block[sel][j].val,
			       vi_size_block[sel][j].size);
			vi_size_block[sel][j].dirty = 0;
		}
	}

	for (j = 0; j < ui_chno; j++) {
		for (i = 0; i < layno; i++) {
			if (ui_attr_block[sel][j][i].dirty == 0x1) {
				memcpy((void *)ui_attr_block[sel][j][i].off,
				       ui_attr_block[sel][j][i].val,
				       ui_attr_block[sel][j][i].size);
				ui_attr_block[sel][j][i].dirty = 0;
			}
		}

		if (ui_haddr_block[sel][j].dirty == 0x1) {
			memcpy((void *)ui_haddr_block[sel][j].off,
			       ui_haddr_block[sel][j].val,
			       ui_haddr_block[sel][j].size);
			ui_haddr_block[sel][j].dirty = 0;
		}

		if (ui_size_block[sel][j].dirty == 0x1) {
			memcpy((void *)ui_size_block[sel][j].off,
			       ui_size_block[sel][j].val,
			       ui_size_block[sel][j].size);
			ui_size_block[sel][j].dirty = 0;
		}
	}

	if (bld_attr_block[sel].dirty == 0x1) {
		memcpy((void *)bld_attr_block[sel].off, bld_attr_block[sel].val,
		       bld_attr_block[sel].size);
		bld_attr_block[sel].dirty = 0;
	}

	if (bld_ctl_block[sel].dirty == 0x1) {
		memcpy((void *)bld_ctl_block[sel].off, bld_ctl_block[sel].val,
		       bld_ctl_block[sel].size);
		bld_ctl_block[sel].dirty = 0;
	}

	if (bld_ck_block[sel].dirty == 0x1) {
		memcpy((void *)bld_ck_block[sel].off, bld_ck_block[sel].val,
		       bld_ck_block[sel].size);
		bld_ck_block[sel].dirty = 0;
	}

	if (bld_out_block[sel].dirty == 0x1) {
		memcpy((void *)bld_out_block[sel].off, bld_out_block[sel].val,
		       bld_out_block[sel].size);
		bld_out_block[sel].dirty = 0;
	}

	return 0;
}

static int de_rtmx_force_dirty(unsigned int sel)
{
	int i, j, ui_chno, vi_chno, layno;

	vi_chno = de_feat_get_num_vi_chns(sel);
	ui_chno = de_feat_get_num_ui_chns(sel);
	layno = LAYER_MAX_NUM_PER_CHN;

	glb_ctl_block[sel].dirty = 1;
	for (j = 0; j < vi_chno; j++) {
		for (i = 0; i < layno; i++)
			vi_attr_block[sel][j][i].dirty = 1;
		vi_fc_block[sel][j].dirty = 1;
		vi_haddr_block[sel][j].dirty = 1;
		vi_size_block[sel][j].dirty = 1;
	}

	for (j = 0; j < ui_chno; j++) {
		for (i = 0; i < layno; i++)
			ui_attr_block[sel][j][i].dirty = 1;
		ui_haddr_block[sel][j].dirty = 1;
		ui_size_block[sel][j].dirty = 1;
	}

	bld_attr_block[sel].dirty = 1;
	bld_ctl_block[sel].dirty = 1;
	bld_ck_block[sel].dirty = 1;
	bld_out_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_init(unsigned int sel, uintptr_t reg_base)
{
	void *memory;
	int i, j, vi_chno, ui_chno, layno;
	uintptr_t glb_base, apb_base, ovl_base;
	int ch_index = 0;

	de_base = reg_base;

	if (sel > de_feat_get_num_screens())
		__wrn("sel %d out of range\n", sel);

	vi_chno = de_feat_get_num_vi_chns(sel);
	ui_chno = de_feat_get_num_ui_chns(sel);
	layno = LAYER_MAX_NUM_PER_CHN;

	glb_base = reg_base + 0x00100000;
	apb_base = reg_base + 0x00101000;
	ovl_base = reg_base + 0x00102000;

	if (sel == 1) {
		glb_base = reg_base + 0x00200000;
		apb_base = reg_base + 0x00201000;
		ovl_base = reg_base + 0x00202000;
	}

	memory = kmalloc(sizeof(struct __glb_reg_t), GFP_KERNEL | __GFP_ZERO);
	if (NULL == memory) {
		__wrn("malloc rtmx global memory fail! size=0x%x\n",
		      (unsigned int)sizeof(struct __glb_reg_t));
		return -1;
	}

	glb_ctl_block[sel].off = glb_base;
	glb_ctl_block[sel].val = memory;
	glb_ctl_block[sel].size = 0x10;
	glb_ctl_block[sel].dirty = 1;

	de_rtmx_set_gld_reg_base(sel, memory);

	for (j = 0; j < vi_chno; j++) {
		memory =
			kmalloc(sizeof(struct __vi_ovl_reg_t),
			GFP_KERNEL | __GFP_ZERO);
		if (NULL == memory) {
			__wrn("malloc video overlay memory fail! size=0x%x\n",
			      (unsigned int)sizeof(struct __vi_ovl_reg_t));
			return -1;
		} else {
			__inf("malloc memory ok(0x%p) for video channel\n",
			      (void *)memory);
		}
		for (i = 0; i < layno; i++) {
			vi_attr_block[sel][j][i].off =
			    ovl_base + ch_index * 0x00001000 + i * 0x30;
			vi_attr_block[sel][j][i].val = (memory + i * 0x30);
			vi_attr_block[sel][j][i].size = 0x30;
			vi_attr_block[sel][j][i].dirty = 1;
		}

		vi_fc_block[sel][j].off =
		    ovl_base + ch_index * 0x00001000 + 0xc0;
		vi_fc_block[sel][j].val = (memory + 0xc0);
		vi_fc_block[sel][j].size = 0x10;
		vi_fc_block[sel][j].dirty = 1;

		vi_haddr_block[sel][j].off =
		    ovl_base + ch_index * 0x00001000 + 0xd0;
		vi_haddr_block[sel][j].val = (memory + 0xd0);
		vi_haddr_block[sel][j].size = 0x18;
		vi_haddr_block[sel][j].dirty = 1;

		vi_size_block[sel][j].off =
		    ovl_base + ch_index * 0x00001000 + 0xe8;
		vi_size_block[sel][j].val = (memory + 0xe8);
		vi_size_block[sel][j].size = 0x18;
		vi_size_block[sel][j].dirty = 1;
		de_rtmx_set_overlay_reg_base(sel, j, memory);

		ch_index++;
	}

	for (j = 0; j < ui_chno; j++) {

		memory =
			kmalloc(sizeof(struct __ui_ovl_reg_t),
			GFP_KERNEL | __GFP_ZERO);
		if (NULL == memory) {
			__wrn("malloc ui overlay memory fail! size=0x%x\n",
			      (unsigned int)sizeof(struct __ui_ovl_reg_t));
			return -1;
		}

		for (i = 0; i < layno; i++) {
			ui_attr_block[sel][j][i].off =
			    ovl_base + ch_index * 0x00001000 + i * 0x20;
			ui_attr_block[sel][j][i].val = (memory + i * 0x20);
			ui_attr_block[sel][j][i].size = 0x20;
			ui_attr_block[sel][j][i].dirty = 1;
		}

		ui_haddr_block[sel][j].off =
		    ovl_base + ch_index * 0x00001000 + 0x80;
		ui_haddr_block[sel][j].val = (memory + 0x80);
		ui_haddr_block[sel][j].size = 0x8;
		ui_haddr_block[sel][j].dirty = 1;

		ui_size_block[sel][j].off =
		    ovl_base + ch_index * 0x00001000 + 0x88;
		ui_size_block[sel][j].val = (memory + 0x88);
		ui_size_block[sel][j].size = 0x4;
		ui_size_block[sel][j].dirty = 1;

		de_rtmx_set_overlay_reg_base(sel, j + vi_chno, memory);

		ch_index++;
	}

	memory = kmalloc(sizeof(struct __bld_reg_t), GFP_KERNEL | __GFP_ZERO);
	if (NULL == memory) {
		__wrn("malloc blending memory fail! size=0x%x\n",
		      (unsigned int)sizeof(struct __bld_reg_t));
		return -1;
	}

	bld_attr_block[sel].off = apb_base;
	bld_attr_block[sel].val = memory;
	bld_attr_block[sel].size = 0x44;
	bld_attr_block[sel].dirty = 1;

	bld_ctl_block[sel].off = apb_base + 0x80;
	bld_ctl_block[sel].val = (memory + 0x80);
	bld_ctl_block[sel].size = 0x20;
	bld_ctl_block[sel].dirty = 1;

	bld_ck_block[sel].off = apb_base + 0xb0;
	bld_ck_block[sel].val = (memory + 0xb0);
	bld_ck_block[sel].size = 0x4c;
	bld_ck_block[sel].dirty = 1;

	bld_out_block[sel].off = apb_base + 0xfc;
	bld_out_block[sel].val = (memory + 0xfc);
	bld_out_block[sel].size = 0x4;
	bld_out_block[sel].dirty = 1;

	de_rtmx_set_bld_reg_base(sel, memory);

	return 0;
}

/**
 *function    : de_rtmx_set_gld_reg_base(unsigned int sel, unsigned int base)
 *description : set de reg base
 *parameters  :
 *              sel         <rtmx select>
 *              base        <reg base>
 *return      :
 *              success
 */
int de_rtmx_set_gld_reg_base(unsigned int sel, void *base)
{
	__inf("sel=0x%x, addr=0x%p\n", sel, base);
	de200_rtmx[sel].glb_ctl = (struct __glb_reg_t *)base;

	return 0;
}

/**
 *function    : de_rtmx_set_bld_reg_base(unsigned int sel, unsigned int base)
 *description : set de reg base
 *parameters  :
 *              sel         <rtmx select>
 *              base        <reg base>
 *return      :
 *              success
 */
int de_rtmx_set_bld_reg_base(unsigned int sel, void *base)
{
	__inf("sel=%d, base=0x%p\n", sel, base);
	de200_rtmx[sel].bld_ctl = (struct __bld_reg_t *) base;

	return 0;
}

/**
 *function   : de_rtmx_set_overlay_reg_base(unsigned int sel,
 *                      unsigned int chno, unsigned int base)
 *description: set de reg base
 *parameters :
 *             sel         <rtmx select>
 *             chno        <overlay select>
 *             base        <reg base>
 *return     :
 *             success
 */
int de_rtmx_set_overlay_reg_base(unsigned int sel, unsigned int chno,
				 void *base)
{
	int vi_chno = de_feat_get_num_vi_chns(sel);

	__inf("sel=0x%x, overlayer %d, addr=0x%p\n", sel, chno, base);

	if (chno < vi_chno) {
		de200_rtmx[sel].vi_ovl[chno] = (struct __vi_ovl_reg_t *) base;
	} else {
		de200_rtmx[sel].ui_ovl[chno - vi_chno] =
		    (struct __ui_ovl_reg_t *) base;
	}

	return 0;
}

int de_rtmx_set_display_size(unsigned int sel, unsigned int width,
			     unsigned int height)
{
	de200_rtmx[sel].glb_ctl->glb_size.bits.width =
	    width == 0 ? 0 : width - 1;
	de200_rtmx[sel].glb_ctl->glb_size.bits.height =
	    height == 0 ? 0 : height - 1;

	glb_ctl_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_set_dbuff_rdy(unsigned int sel)
{
	de200_rtmx[sel].glb_ctl->glb_dbuff.dwval = 0x1;

	glb_ctl_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_set_enable(unsigned int sel, unsigned int en)
{
	/* de200_rtmx[sel].glb_ctl->glb_ctl.bits.finish_irq_en = en&0x1; */

	/* 0:write back fetch data after dep;
	 * 1:write back fetch data before dep
	 */
	de200_rtmx[sel].glb_ctl->glb_ctl.bits.rtwb_port = 0x1;
	de200_rtmx[sel].glb_ctl->glb_ctl.bits.rt_en = en & 0x1;

	/* glb_ctl_block[sel].dirty      = 1;  */
	if (en)
		de_rtmx_force_dirty(sel);

	return 0;
}

int de_rtmx_query_irq(unsigned int sel)
{
	unsigned int irq_flag;
	uintptr_t base = glb_ctl_block[sel].off;

	irq_flag = readl((void __iomem *)(base + 0x04));
	if (irq_flag & 0x1) {
		writel(irq_flag, (void __iomem *)(base + 0x04));
		return 1;
	}

	return 0;
}

int de_rtmx_enable_irq(unsigned int sel, unsigned int en)
{
	unsigned int irq_flag;
	uintptr_t base = glb_ctl_block[sel].off;

	irq_flag = readl((void __iomem *)(base + 0x0));
	irq_flag &= (~(0x1 << 4));
	irq_flag |= (en & 0x1) << 4;
	writel(irq_flag, (void __iomem *)(base + 0x0));

	return 0;
}

/**
 *function       : de_rtmx_set_lay_cfg(unsigned int sel,
 *              unsigned int chno, unsigned int layno, struct __lay_para_t *cfg)
 *description    : set de layer config
 *parameters     :
 *                 sel         <rtmx select>
 *                 chno        <overlay channel number>
 *                 layno       <layer number>
 *                 cfg         <layer config data>
 *return         :
 *                 success
 */
int de_rtmx_set_lay_cfg(unsigned int sel, unsigned int chno, unsigned int layno,
			struct __lay_para_t *cfg)
{
	int fmt, ui_sel;
	int vi_chno = de_feat_get_num_vi_chns(sel);

	if (chno >= vi_chno) {
		struct __ui_lay_reg_t *lyr_cfg =
		    &de200_rtmx[sel].ui_ovl[chno-vi_chno]->ui_lay_cfg[layno];

		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_lay_cfg[layno].lay_attr.
		    bits.lay_en = cfg->en;
		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_lay_cfg[layno].lay_attr.
		    bits.lay_alpmod = cfg->alpha_mode;
		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_lay_cfg[layno].lay_attr.
		    bits.lay_fcolor_en = cfg->fcolor_en;
		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_lay_cfg[layno].lay_attr.
		    bits.lay_fmt = cfg->fmt;
		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_lay_cfg[layno].lay_attr.
		    bits.lay_alpctl = cfg->premul_ctl;
		/* Using burst 4 for better efficiency */
		lyr_cfg->lay_attr.bits.burst = 0x1;
		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_lay_cfg[layno].lay_attr.
		    bits.lay_top_down = cfg->top_bot_en;
		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_lay_cfg[layno].lay_attr.
		    bits.lay_alpha = cfg->alpha;

		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_lay_cfg[layno].lay_size.
		    bits.lay_width = cfg->layer.w == 0 ? 0 : cfg->layer.w - 1;
		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_lay_cfg[layno].lay_size.
		    bits.lay_height = cfg->layer.h == 0 ? 0 : cfg->layer.h - 1;

		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_lay_cfg[layno].lay_coor.
		    bits.lay_coorx = cfg->layer.x;
		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_lay_cfg[layno].lay_coor.
		    bits.lay_coory = cfg->layer.y;

		ui_attr_block[sel][chno - vi_chno][layno].dirty = 1;
	} else {
		struct __vi_lay_reg_t *lyr_cfg =
		    &de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno];

		if (DE_FORMAT_YUV422_I_VYUY == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0x0;
		} else if (DE_FORMAT_YUV422_I_YVYU == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0x1;
		} else if (DE_FORMAT_YUV422_I_UYVY == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0x2;
		} else if (DE_FORMAT_YUV422_I_YUYV == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0x3;
		} else if (DE_FORMAT_YUV422_SP_VUVU == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0x5;
		} else if (DE_FORMAT_YUV422_SP_UVUV == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0x4;
		} else if (DE_FORMAT_YUV422_P == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0x6;
		} else if (DE_FORMAT_YUV420_SP_VUVU == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0x9;
		} else if (DE_FORMAT_YUV420_SP_UVUV == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0x8;
		} else if (DE_FORMAT_YUV420_P == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0xa;
		} else if (DE_FORMAT_YUV411_SP_VUVU == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0xd;
		} else if (DE_FORMAT_YUV411_SP_UVUV == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0xc;
		} else if (DE_FORMAT_YUV411_P == cfg->fmt) {
			ui_sel = 0x0;
			fmt = 0xe;
		} else {
			ui_sel = 0x1;
			fmt = cfg->fmt;
		}

		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits.
		    lay_en = cfg->en;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits.
		    lay_fcolor_en = cfg->fcolor_en;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits.
		    lay_fmt = fmt;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits.
		    ui_sel = ui_sel;
		/* Using burst 4 for better efficiency */
		lyr_cfg->lay_attr.bits.yburst = 0x1;
		lyr_cfg->lay_attr.bits.uburst = 0x1;
		lyr_cfg->lay_attr.bits.vburst = 0x1;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.bits.
		    lay_top_down = cfg->top_bot_en;

		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_size.bits.
		    lay_width = cfg->layer.w == 0 ? 0 : cfg->layer.w - 1;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_size.bits.
		    lay_height = cfg->layer.h == 0 ? 0 : cfg->layer.h - 1;

		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_coor.bits.
		    lay_coorx = cfg->layer.x;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_coor.bits.
		    lay_coory = cfg->layer.y;

		vi_attr_block[sel][chno][layno].dirty = 1;
	}

	return 0;
}

/*
 *function       : de_rtmx_set_lay_haddr(unsigned int sel, unsigned int chno,
 *                     unsigned int layno, unsigned char top_bot_en,
 *                     unsigned char *haddr_t, unsigned char *haddr_b)
 *description    : set de high address for layers
 *parameters     :
 *                 sel         <rtmx select>
 *                 chno        <overlay channel number>
 *                 haddr_t     <layer high top address data>
 *                 haddr_b     <layer high bottom address data>
 *return         :
 *                 success
 */
int de_rtmx_set_lay_haddr(unsigned int sel, unsigned int chno,
			  unsigned int layno, unsigned char top_bot_en,
			  unsigned char *haddr_t, unsigned char *haddr_b)
{
	unsigned int haddr, mask;
	int vi_chno = de_feat_get_num_vi_chns(sel);

	switch (layno) {
	case 0:
		mask = 0xffffff00;
		break;
	case 1:
		mask = 0xffff00ff;
		break;
	case 2:
		mask = 0xff00ffff;
		break;
	default:
		mask = 0x00ffffff;
		break;
	}

	if (chno >= vi_chno) {

		haddr =
		    de200_rtmx[sel].ui_ovl[chno -
		    vi_chno]->ui_lay_top_haddr.dwval & mask;
		de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_top_haddr.dwval =
		    haddr + (haddr_t[0] << layno);

		if (top_bot_en) {
			haddr =
			    de200_rtmx[sel].ui_ovl[chno - vi_chno]
			    ->ui_lay_bot_haddr.dwval & mask;
			de200_rtmx[sel].ui_ovl[chno - vi_chno]
			    ->ui_lay_bot_haddr.dwval =
			    haddr + (haddr_b[0] << layno);
		}

		ui_haddr_block[sel][chno - vi_chno].dirty = 1;
	} else {
		haddr =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[0].dwval
		    & mask;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[0].dwval =
		    haddr + (haddr_t[0] << layno);
		haddr =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[1].dwval
		    & mask;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[1].dwval =
		    haddr + (haddr_t[1] << layno);
		haddr =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[2].dwval
		    & mask;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[2].dwval =
		    haddr + (haddr_t[2] << layno);

		if (top_bot_en) {
			haddr =
			    de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[0].
			    dwval & mask;
			de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[0].dwval
			    = haddr + (haddr_b[0] << layno);
			haddr =
			    de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[1].
			    dwval & mask;
			de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[1].dwval
			    = haddr + (haddr_b[1] << layno);
			haddr =
			    de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[2].
			    dwval & mask;
			de200_rtmx[sel].vi_ovl[chno]->vi_lay_bot_haddr[2].dwval
			    = haddr + (haddr_b[2] << layno);
		}

		vi_haddr_block[sel][chno].dirty = 1;
	}

	return 0;
}

/**
 *function       : de_rtmx_set_lay_laddr(unsigned int sel, unsigned int chno,
 *                 unsigned int layno, unsigned char fmt,struct de_rect crop,
 *                 unsigned int *size, enum de_3d_in_mode trdinmode,
 *                  unsigned int *addr,unsigned char *haddr)
 *description    : set de low address for layer
 *parameters     :
 *                 sel         <rtmx select>
 *                 chno        <overlay channel number>
 *                 layno       <layer number>
 *                 fmt         <layer data data format>
 *return         :
 *                 success
 */
int de_rtmx_set_lay_laddr(unsigned int sel, unsigned int chno,
			unsigned int layno, unsigned char fmt,
			struct de_rect crop, unsigned int *size,
			unsigned int *align, enum de_3d_in_mode trdinmode,
			unsigned int *addr, unsigned char *haddr)
{
	long long addr_off[3];
	unsigned int pitch[3];
	unsigned int x0, x1, y0, y1, ycnt, ucnt;
	int vi_chno = de_feat_get_num_vi_chns(sel);

	x0 = crop.x;
	y0 = crop.y;
	x1 = y1 = 0;
	ycnt = ucnt = 0;

	if (fmt <= DE_FORMAT_BGRX_8888) {
		ycnt = 4;
	} else if (fmt <= DE_FORMAT_BGR_888) {
		ycnt = 3;
	} else if (fmt <= DE_FORMAT_BGRA_5551) {
		ycnt = 2;
	} else if (fmt <= DE_FORMAT_YUV422_I_VYUY) {
		ycnt = 2;
		ucnt = 0;
	} else if (fmt == DE_FORMAT_YUV422_P) {
		ycnt = 1;
		ucnt = 1;
		x1 = x0 / 2;
		y1 = y0;
	}
	/* YUV422 */
	else if (fmt == DE_FORMAT_YUV420_P) {
		ycnt = 1;
		ucnt = 1;
		x1 = x0 / 2;
		y1 = y0 / 2;
	}
	/* YUV420 */
	else if (fmt == DE_FORMAT_YUV411_P) {
		ycnt = 1;
		ucnt = 1;
		x1 = x0 / 4;
		y1 = y0;
	}
	/* YUV411 */
	else if (fmt <= DE_FORMAT_YUV422_SP_VUVU) {
		ycnt = 1;
		ucnt = 2;
		x1 = x0 / 2;
		y1 = y0;
	} else if (fmt <= DE_FORMAT_YUV420_SP_VUVU) {
		ycnt = 1;
		ucnt = 2;
		x1 = x0 / 2;
		y1 = y0 / 2;
	} else if (fmt <= DE_FORMAT_YUV411_SP_VUVU) {
		ycnt = 1;
		ucnt = 2;
		x1 = x0 / 4;
		y1 = y0;
	} else {
		ycnt = 4;
	}

	pitch[0] = DISPALIGN(size[0] * ycnt, align[0]);
	pitch[1] = DISPALIGN(size[1] * ucnt, align[1]);
	pitch[2] = DISPALIGN(size[2] * ucnt, align[2]);

	if (trdinmode == DE_3D_SRC_MODE_LI)
		addr_off[0] =
		    addr[0] + de_rtmx_get_li_addr_offset(size[0], align[0], x0,
			    y0, ycnt);
	else
		addr_off[0] = addr[0] + pitch[0] * y0 + x0 * ycnt;
		/* Y/ARGB */

	haddr[0] = (addr_off[0] >> 32) & 0xff;
	if (chno >= vi_chno) {
		de200_rtmx[sel].ui_ovl[chno - vi_chno]
		    ->ui_lay_cfg[layno].lay_pitch.dwval = pitch[0];
		de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].
		    lay_top_laddr.dwval = (addr_off[0] & 0xffffffff);
		de200_rtmx[sel].ui_ovl[chno - vi_chno]->
		    ui_lay_cfg[layno].lay_bot_laddr.dwval = 0x0;

		ui_attr_block[sel][chno - vi_chno][layno].dirty = 1;
	} else {
		if (trdinmode == DE_3D_SRC_MODE_LI) {
			addr_off[1] =
			    addr[1] + de_rtmx_get_li_addr_offset(size[1],
								 align[1], x1,
								 y1, ucnt);
			addr_off[2] =
			    addr[2] + de_rtmx_get_li_addr_offset(size[2],
								 align[2], x1,
								 y1, ucnt);
		} else {
			addr_off[1] = addr[1] + pitch[1] * y1 + x1 * ucnt;
			/* UV/U */
			addr_off[2] = addr[2] + pitch[2] * y1 + x1 * ucnt;
			/* V */
		}

		haddr[1] = (addr_off[1] >> 32) & 0xff;
		haddr[2] = (addr_off[2] >> 32) & 0xff;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_pitch[0].
		    dwval = pitch[0];
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_pitch[1].
		    dwval = pitch[1];
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_pitch[2].
		    dwval = pitch[2];

		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_top_laddr[0].dwval = (addr_off[0] & 0xffffffff);
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_top_laddr[1].dwval = (addr_off[1] & 0xffffffff);
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_top_laddr[2].dwval = (addr_off[2] & 0xffffffff);

		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_bot_laddr[0].dwval = 0x0;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_bot_laddr[1].dwval = 0x0;
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_bot_laddr[2].dwval = 0x0;

		vi_attr_block[sel][chno][layno].dirty = 1;
	}

	return 0;
}

int de_rtmx_get_3d_in_single_size(enum de_3d_in_mode inmode,
	struct de_rect64 *size)
{

	switch (inmode) {
	case DE_3D_SRC_MODE_TB:
		size->w = size->w;
		size->h = size->h >> 1;
		size->x = size->x;
		size->y = size->y;
		break;
	case DE_3D_SRC_MODE_SSF:
	case DE_3D_SRC_MODE_SSH:
		size->w = size->w >> 1;
		size->h = size->h;
		size->x = size->x;
		size->y = size->y;
		break;
	case DE_3D_SRC_MODE_LI:
		size->w = size->w;
		size->h = size->h >> 1;
		size->x = size->x;
		size->y = size->y >> 1;
		break;
	case DE_3D_SRC_MODE_FP:
		size->w = size->w;
		size->h = size->h;
		size->x = size->x;
		size->y = size->y;
		break;
	default:
		/* undefine input mode */
		break;
	}

	return 0;
}

int de_rtmx_get_3d_in(unsigned char fmt, struct de_rect crop,
			struct de_fb *size, unsigned int *align,
			enum de_3d_in_mode trdinmode, unsigned int *addr,
			unsigned int *trd_addr, unsigned int *pitch,
			unsigned int *pitchr, unsigned int *lay_laddr)
{
	unsigned int ycnt, ucnt, data_type;
	unsigned int image_w0, image_w1, image_w2, image_h0, image_h1, image_h2;

	ycnt = ucnt = 0;
	if (trdinmode == DE_3D_SRC_NORMAL)
		return -1;

	if (fmt <= DE_FORMAT_BGRX_8888) {
		ycnt = 4;
		data_type = 0x0;
	} else if (fmt <= DE_FORMAT_BGR_888) {
		ycnt = 3;
		data_type = 0x0;
	} else if (fmt <= DE_FORMAT_BGRA_5551) {
		ycnt = 2;
		data_type = 0x0;
	} else if (fmt <= DE_FORMAT_YUV422_I_VYUY) {
		ycnt = 2;
		data_type = 0x0;
		ucnt = 0;
	} else if (fmt == DE_FORMAT_YUV422_P) {
		ycnt = 1;
		data_type = 0x2;
		ucnt = 1;
	}
	/* YUV422 */
	else if (fmt == DE_FORMAT_YUV420_P) {
		ycnt = 1;
		data_type = 0x2;
		ucnt = 1;
	}
	/* YUV420 */
	else if (fmt == DE_FORMAT_YUV411_P) {
		ycnt = 1;
		data_type = 0x2;
		ucnt = 1;
	}
	/* YUV411 */
	else if (fmt <= DE_FORMAT_YUV422_SP_VUVU) {
		ycnt = 1;
		data_type = 0x1;
		ucnt = 2;
	} else if (fmt <= DE_FORMAT_YUV420_SP_VUVU) {
		ycnt = 1;
		data_type = 0x1;
		ucnt = 2;
	} else if (fmt <= DE_FORMAT_YUV411_SP_VUVU) {
		ycnt = 1;
		data_type = 0x1;
		ucnt = 2;
	} else {
		ycnt = 4;
		data_type = 0x0;
	}

	switch (fmt) {
	case DE_FORMAT_YUV420_P:
	case DE_FORMAT_YUV420_SP_VUVU:
	case DE_FORMAT_YUV420_SP_UVUV:
		image_w0 = crop.w;
		image_w2 = image_w1 = crop.w >> 1;
		image_h0 = crop.h;
		image_h2 = image_h1 = crop.h >> 1;
		break;
	case DE_FORMAT_YUV422_P:
	case DE_FORMAT_YUV422_SP_VUVU:
	case DE_FORMAT_YUV422_SP_UVUV:
		image_w0 = crop.w;
		image_w2 = image_w1 = crop.w >> 1;
		image_h0 = crop.h;
		image_h2 = image_h1 = image_h0;
		break;
	case DE_FORMAT_YUV411_P:
	case DE_FORMAT_YUV411_SP_VUVU:
	case DE_FORMAT_YUV411_SP_UVUV:
		image_w0 = crop.w;
		image_w2 = image_w1 = crop.w >> 2;
		image_h0 = crop.h;
		image_h2 = image_h1 = image_h0;
		break;
	default:
		image_w0 = crop.w;
		image_w2 = image_w1 = image_w0;
		image_h0 = crop.h;
		image_h2 = image_h1 = image_h0;
		break;
	}
	/* planar */
	if (data_type == 0x2) {
		if ((trdinmode == DE_3D_SRC_MODE_TB)) {
			pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]);
			pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]);
			pitchr[2] = pitch[2] = DISPALIGN(size[2].w, align[2]);

			lay_laddr[0] = pitch[0] * image_h0 + addr[0];
			lay_laddr[1] = pitch[1] * image_h1 + addr[1];
			lay_laddr[2] = pitch[2] * image_h2 + addr[2];

		} else if ((trdinmode == DE_3D_SRC_MODE_FP)) {
			pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]);
			pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]);
			pitchr[2] = pitch[2] = DISPALIGN(size[2].w, align[2]);

			lay_laddr[0] = trd_addr[0];
			lay_laddr[1] = trd_addr[1];
			lay_laddr[2] = trd_addr[2];

		} else if ((trdinmode == DE_3D_SRC_MODE_SSF)
			   || (trdinmode == DE_3D_SRC_MODE_SSH)) {
			pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]);
			pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]);
			pitchr[2] = pitch[2] = DISPALIGN(size[2].w, align[2]);

			lay_laddr[0] = image_w0 + addr[0];
			lay_laddr[1] = image_w1 + addr[1];
			lay_laddr[2] = image_w2 + addr[2];
		} else if ((trdinmode == DE_3D_SRC_MODE_LI)) {
			pitchr[0] = pitch[0] =
			    (DISPALIGN(size[0].w, align[0])) << 1;
			pitchr[1] = pitch[1] =
			    (DISPALIGN(size[1].w, align[1])) << 1;
			pitchr[2] = pitch[2] =
			    (DISPALIGN(size[2].w, align[2])) << 1;

			lay_laddr[0] = DISPALIGN(size[0].w, align[0]) + addr[0];
			lay_laddr[1] = DISPALIGN(size[1].w, align[1]) + addr[1];
			lay_laddr[2] = DISPALIGN(size[2].w, align[2]) + addr[2];
		}
	} else if (data_type == 0x0)
		/* interleaved */
	{
		if ((trdinmode == DE_3D_SRC_MODE_FP)) {
			pitchr[0] = pitch[0] =
			    DISPALIGN(size[0].w * ycnt, align[0]) / ycnt;
			pitchr[1] = pitch[1] = 0;
			pitchr[2] = pitch[2] = 0;

			lay_laddr[0] = trd_addr[0];
			lay_laddr[1] = 0;
			lay_laddr[2] = 0;
		} else if ((trdinmode == DE_3D_SRC_MODE_TB)) {
			pitchr[0] = pitch[0] =
			    DISPALIGN(size[0].w * ycnt, align[0]) / ycnt;
			pitchr[1] = pitch[1] = 0;
			pitchr[2] = pitch[2] = 0;

			lay_laddr[0] = pitch[0] * image_h0 * ycnt + addr[0];
			lay_laddr[1] = 0;
			lay_laddr[2] = 0;
		} else if ((trdinmode == DE_3D_SRC_MODE_SSF)
			   || (trdinmode == DE_3D_SRC_MODE_SSH)) {

			pitchr[0] = pitch[0] =
			    DISPALIGN(size[0].w * ycnt, align[0]) / ycnt;
			pitchr[1] = pitch[1] = 0;
			pitchr[2] = pitch[2] = 0;

			lay_laddr[0] = image_w0 * ycnt + addr[0];
			lay_laddr[1] = 0;
			lay_laddr[2] = 0;
		} else if ((trdinmode == DE_3D_SRC_MODE_LI)) {
			pitchr[0] = pitch[0] =
			    (DISPALIGN(size[0].w, align[0])) << 1;
			pitchr[1] = pitch[1] = 0;
			pitchr[2] = pitch[2] = 0;

			lay_laddr[0] =
			    (DISPALIGN(size[0].w, align[0])) * ycnt + addr[0];
			lay_laddr[1] = 0;
			lay_laddr[2] = 0;
		}
	} else if (data_type == 0x1)
		/* semi-planar */
	{
		if ((trdinmode == DE_3D_SRC_MODE_SSF)
		    || (trdinmode == DE_3D_SRC_MODE_SSH)) {
			pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]);
			pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]);
			pitchr[2] = pitch[2] = 0;

			lay_laddr[0] = image_w0 + addr[0];
			lay_laddr[1] = (image_w1 * ucnt) + addr[1];
			lay_laddr[2] = 0;
		} else if (trdinmode == DE_3D_SRC_MODE_TB) {
			pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]);
			pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]);
			pitchr[2] = pitch[2] = 0;

			lay_laddr[0] = pitch[0] * image_h0 + addr[0];
			lay_laddr[1] = pitch[1] * image_h1 * ucnt + addr[1];
			lay_laddr[2] = 0;
		} else if (trdinmode == DE_3D_SRC_MODE_FP) {
			pitchr[0] = pitch[0] = DISPALIGN(size[0].w, align[0]);
			pitchr[1] = pitch[1] = DISPALIGN(size[1].w, align[1]);
			pitchr[2] = pitch[2] = 0;

			lay_laddr[0] = trd_addr[0];
			lay_laddr[1] = trd_addr[1];
			lay_laddr[2] = 0;
		} else if (trdinmode == DE_3D_SRC_MODE_LI) {
			pitchr[0] = pitch[0] =
			    (DISPALIGN(size[0].w, align[0])) << 1;
			pitchr[1] = pitch[1] =
			    (DISPALIGN(size[1].w, align[1])) << 1;
			pitchr[2] = pitch[2] = 0;

			lay_laddr[0] = addr[0] + DISPALIGN(size[1].w, align[1]);
			lay_laddr[1] =
			    addr[1] + (DISPALIGN(size[1].w, align[1])) * ucnt;
			lay_laddr[2] = 0;
		}
	}

	return 0;
}

int de_rtmx_get_li_addr_offset(unsigned int size, unsigned int align,
			       unsigned int x, unsigned int y, unsigned int cnt)
{
	unsigned int offset;

	offset = DISPALIGN(size, align) * (y >> 1) + x * cnt;

	return offset;
}

int de_rtmx_get_3d_out(struct de_rect frame0, unsigned int scn_w,
			unsigned int scn_h, enum de_3d_out_mode trdoutmode,
			struct de_rect *frame1)
{
	switch (trdoutmode) {
	case DE_3D_OUT_MODE_CI_1:
	case DE_3D_OUT_MODE_CI_2:
	case DE_3D_OUT_MODE_CI_3:
	case DE_3D_OUT_MODE_CI_4:
	case DE_3D_OUT_MODE_SSF:
	case DE_3D_OUT_MODE_SSH:
		{
			frame1->x = frame0.x + scn_w;
			frame1->y = frame0.y;
			frame1->w = frame0.w;
			frame1->h = frame0.h;
			break;
		}
	case DE_3D_OUT_MODE_TB:
	case DE_3D_OUT_MODE_FP:
		{
			frame1->x = frame0.x;
			frame1->y = frame0.y + (scn_h >> 1);
			frame1->w = frame0.w;
			frame1->h = frame0.h;
			break;
		}
	case DE_3D_OUT_MODE_LI:
		/* enable remapping */
		{
			frame1->x = frame0.x + scn_w;
			frame1->y = frame0.y;
			frame1->w = frame0.w;
			frame1->h = frame0.h;
			break;
		}
	case DE_3D_OUT_MODE_LIRGB:
		/* enable remapp */
		{
			frame1->x = frame0.x;
			frame1->y = frame0.y + scn_h;
			frame1->w = frame0.w;
			frame1->h = frame0.h;
			break;
		}
	default:
		break;
	}
	__inf("frame0=<%d,%d,%d,%d>\n", frame0.x, frame0.y, frame0.w, frame0.h);
	__inf("frame1=<%d,%d,%d,%d>\n", frame1->x, frame1->y, frame1->w,
	      frame1->h);

	return 0;
}

int de_rtmx_set_lay_fcolor(unsigned int sel, unsigned int chno,
			   unsigned int layno, unsigned char en,
			   unsigned char fmt, unsigned int color)
{
	unsigned int Y, U, V;
	int vi_chno = de_feat_get_num_vi_chns(sel);

	if (chno >= vi_chno) {
		de200_rtmx[sel].ui_ovl[chno - vi_chno]
		    ->ui_lay_cfg[layno].lay_fcolor.dwval = en ? color : 0;

		ui_attr_block[sel][chno - vi_chno][layno].dirty = 1;
	} else {
		Y = color & 0xff0000;
		switch (fmt) {
		case DE_FORMAT_YUV422_I_UYVY:
		case DE_FORMAT_YUV422_I_YUYV:
		case DE_FORMAT_YUV422_SP_UVUV:
		case DE_FORMAT_YUV420_SP_UVUV:
		case DE_FORMAT_YUV411_SP_UVUV:
			U = (color & 0xff) << 8;
			V = (color & 0xff00) >> 8;
			break;
		default:
			U = (color & 0xff00);
			V = (color & 0xff);
			break;
		}
		de200_rtmx[sel].vi_ovl[chno]->vi_lay_fcolor[layno].dwval = en ?
		    ((0xFF << 24) | Y | U | V) : 0;

		vi_fc_block[sel][chno].dirty = 1;
	}

	return 0;
}

int de_rtmx_set_overlay_size(unsigned int sel, unsigned int chno,
			     unsigned int w, unsigned int h)
{
	int vi_chno = de_feat_get_num_vi_chns(sel);

	if (chno >= vi_chno) {
		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_ovl_size.bits.ovl_width =
		    w == 0 ? 0 : w - 1;
		de200_rtmx[sel].ui_ovl[chno -
				       vi_chno]->ui_ovl_size.bits.ovl_height =
		    h == 0 ? 0 : h - 1;

		ui_size_block[sel][chno - vi_chno].dirty = 1;
	} else {
		de200_rtmx[sel].vi_ovl[chno]->vi_ovl_size[0].bits.ovl_width =
		    w == 0 ? 0 : w - 1;
		de200_rtmx[sel].vi_ovl[chno]->vi_ovl_size[0].bits.ovl_height =
		    h == 0 ? 0 : h - 1;

		vi_size_block[sel][chno].dirty = 1;
	}

	return 0;
}

static int de_rtmx_get_coarse_fac(unsigned int sel, unsigned int ovl_w,
				  unsigned int ovl_h, unsigned int vsu_outw,
				  unsigned int vsu_outh, unsigned int fmt,
				  unsigned int lcd_fps, unsigned int lcd_height,
				  unsigned int de_freq_mhz, unsigned int *yhm,
				  unsigned int *yhn, unsigned int *yvm,
				  unsigned int *yvn, unsigned int *chm,
				  unsigned int *chn, unsigned int *cvm,
				  unsigned int *cvn, unsigned int *midyw,
				  unsigned int *midyh, unsigned int *midcw,
				  unsigned int *midch)
{
	unsigned int format, wshift, hshift, status;
	unsigned int tmpyhm, tmpyhn, tmpyvm, tmpyvn;
	unsigned int tmp, required_speed_ability;
	unsigned long long update_speed_ability;
	unsigned int linebuf = 2048;

	/* 0-422, 1-420, 2-411, 3-no mean */
	switch (fmt) {
	case DE_FORMAT_YUV422_I_YVYU:
	case DE_FORMAT_YUV422_I_YUYV:
	case DE_FORMAT_YUV422_I_UYVY:
	case DE_FORMAT_YUV422_I_VYUY:
	case DE_FORMAT_YUV422_P:
	case DE_FORMAT_YUV422_SP_UVUV:
	case DE_FORMAT_YUV422_SP_VUVU:
		format = 0;
		break;
	case DE_FORMAT_YUV420_P:
	case DE_FORMAT_YUV420_SP_UVUV:
	case DE_FORMAT_YUV420_SP_VUVU:
		format = 1;
		break;
	case DE_FORMAT_YUV411_P:
	case DE_FORMAT_YUV411_SP_UVUV:
	case DE_FORMAT_YUV411_SP_VUVU:
		format = 2;
		break;
	default:
		format = 3;
		break;
	}

	if (format == 0) {
		wshift = 1;
		hshift = 0;
	} else if (format == 1) {
		wshift = 1;
		hshift = 1;
	} else if (format == 2) {
		wshift = 2;
		hshift = 0;
	} else {
		wshift = 0;
		hshift = 0;
	}

	/* floor Y channel size */
	ovl_w = ovl_w & (~((1 << wshift) - 1));
	ovl_h = ovl_h & (~((1 << hshift) - 1));

	status = 0x0;
	*yhm = 0;
	*yhn = 0;
	*chm = 0;
	*chn = 0;
	*midyw = ovl_w;
	*midcw = ovl_w >> wshift;

	linebuf = de_feat_get_scale_linebuf(sel);
	if ((ovl_w > linebuf)
	    && (ovl_w > 8 * vsu_outw)) {
		tmpyhn = (linebuf < (8 * vsu_outw)) ?
		    linebuf : (8 * vsu_outw);
		status = 0x1;
	/* horizontal Y channel */
	} else if (ovl_w > linebuf) {
		tmpyhn = linebuf;
		status = 0x1;
	} else if (ovl_w > 8 * vsu_outw) {
		tmpyhn = 8 * vsu_outw;
		status = 0x1;
	}

	if (0x1 == status) {
		tmpyhn = tmpyhn & (~((1 << wshift) - 1));
		tmpyhm = ovl_w;
		*yhm = tmpyhm;
		*yhn = tmpyhn;
		*chm = *yhm;
		*chn = *yhn;

		/* actually fetch horizontal pixel Y channel */
		*midyw = tmpyhn;

		/* actually fetch horizontal pixel C channel */
		*midcw = tmpyhn >> wshift;
	}

/*lcd_freq_MHz = lcd_width*lcd_height*lcd_fps/1000000;
 *
 *how many overlay line can be fetched during scanning
 *  one lcd line(consider 80% dram efficiency)
 *update_speed_ability = lcd_width*de_freq_mhz*125/(ovl_w*lcd_freq_MHz);
 */
/* how many overlay line can be fetched
 * during scanning one lcd line(consider 80% dram efficiency)
 */
	tmp = lcd_height * lcd_fps * (ovl_w > vsu_outw ? ovl_w : vsu_outw);
	if (tmp != 0) {
		update_speed_ability =
		    ((unsigned long long)de_freq_mhz * 80000000);
		do_div(update_speed_ability, tmp);
	} else
		update_speed_ability = 0;

/* how many overlay line need to fetch during scanning one lcd line */
	required_speed_ability = vsu_outh == 0 ? 0 : ovl_h * 100 / vsu_outh;

	__inf("%d,%d,%d,%d\n", de_freq_mhz, tmp, vsu_outh, ovl_h);
	__inf("%lld,%d\n", update_speed_ability, required_speed_ability);

	/* vertical Y channel */
	if (update_speed_ability < required_speed_ability) {
		/* if ability < required, use coarse scale */
		unsigned long long tmp2 = update_speed_ability * vsu_outh;
		do_div(tmp2, 100);
		tmpyvn = tmp == 0 ? 0 : (unsigned int)tmp2;
		tmpyvn = tmpyvn & (~((1 << hshift) - 1));
		tmpyvm = ovl_h;
		*yvm = tmpyvm;
		*yvn = tmpyvn;
		*cvm = *yvm;
		*cvn = *yvn;

		/* actually fetch vertical pixel Y channel */
		*midyh = tmpyvn;

		/* actually fetch vertical pixel C channel */
		*midch = tmpyvn >> hshift;
		status |= (0x1 << 1);
	} else if (ovl_h > 4 * vsu_outh) {
		/* to save dram bandwidth when scale down factor more than 4. */
		tmpyvn = 4 * vsu_outh;
		tmpyvn = tmpyvn & (~((1 << hshift) - 1));
		tmpyvm = ovl_h;
		*yvm = tmpyvm;
		*yvn = tmpyvn;
		*cvm = *yvm;
		*cvn = *yvn;

		/* actually fetch vertical pixel Y channel */
		*midyh = tmpyvn;

		/* actually fetch vertical pixel C channel */
		*midch = tmpyvn >> hshift;
		status |= (0x1 << 1);
	} else {
		*yvm = 0;
		*yvn = 0;
		*cvm = 0;
		*cvn = 0;
		*midyh = ovl_h;
		*midch = ovl_h >> hshift;
	}

	return status;
}

/**
 *function   : de_rtmx_set_coarse_fac(unsigned int sel, unsigned int fmt,
 *             unsigned int ovl_w, unsigned int ovl_h,unsigned int vsu_outw,
 *             unsigned int vsu_outh, unsigned int *midyw, unsigned int *midyh,
 *             unsigned int *midcw, unsigned int *midch)
 *description: set de reg base
 *parameters :
 *             sel                                 <rtmx select>
 *             fmt                                 <layer data format>
 *             ovl_w,ovl_h                 <overlay output size>
 *             vsu_outw,vsu_outh   <vsu output size>
 *             *midyw,*midyh               <vsu inputput y size>
 *             *midcw,*midch               <vsu inputput cbcr size>
 *return     :
 *             success
 */
int de_rtmx_set_coarse_fac(unsigned int sel, unsigned char chno,
			   unsigned int fmt, unsigned int lcd_fps,
			   unsigned int lcd_height, unsigned int de_freq_mhz,
			   unsigned int ovl_w, unsigned int ovl_h,
			   unsigned int vsu_outw, unsigned int vsu_outh,
			   unsigned int *midyw, unsigned int *midyh,
			   unsigned int *midcw, unsigned int *midch)
{
	unsigned int yhm, yhn, yvm, yvn, chm, chn, cvm, cvn;
	int status;

	status =
	    de_rtmx_get_coarse_fac(sel, ovl_w, ovl_h, vsu_outw, vsu_outh, fmt,
				   lcd_fps, lcd_height, de_freq_mhz, &yhm, &yhn,
				   &yvm, &yvn, &chm, &chn, &cvm, &cvn, midyw,
				   midyh, midcw, midch);

	de200_rtmx[sel].vi_ovl[chno]->vi_hori_ds[0].bits.m = yhm;
	de200_rtmx[sel].vi_ovl[chno]->vi_hori_ds[0].bits.n = yhn;

	de200_rtmx[sel].vi_ovl[chno]->vi_hori_ds[1].bits.m = chm;
	de200_rtmx[sel].vi_ovl[chno]->vi_hori_ds[1].bits.n = chn;

	de200_rtmx[sel].vi_ovl[chno]->vi_vert_ds[0].bits.m = yvm;
	de200_rtmx[sel].vi_ovl[chno]->vi_vert_ds[0].bits.n = yvn;

	de200_rtmx[sel].vi_ovl[chno]->vi_vert_ds[1].bits.m = cvm;
	de200_rtmx[sel].vi_ovl[chno]->vi_vert_ds[1].bits.n = cvn;

	vi_size_block[sel][chno].dirty = 1;

	return status;
}

int de_rtmx_set_pf_en(unsigned int sel, unsigned char *pen)
{
	unsigned char fen[4] = { 1, 0, 0, 0 };

	de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p0_en = pen[0];
	de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p1_en = pen[1];
	de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p2_en = pen[2];
	de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p3_en = pen[3];

	de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p0_fcolor_en = fen[0];
	de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p1_fcolor_en = fen[1];
	de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p2_fcolor_en = fen[2];
	de200_rtmx[sel].bld_ctl->bld_fcolor_ctl.bits.p3_fcolor_en = fen[3];

	bld_attr_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_set_pipe_cfg(unsigned int sel, unsigned char pno,
			 unsigned int color, struct de_rect bldrc)
{
	/* fix the pipe fill color to 0xff000000(alpha=1)
	 * actually, we just want to fix the fill color of the bottom pipe
	 * so only the fill color function of the bottom pipe is enabled
	 * cause:
	 * co = cs + cb * (1 - as),
	 * ao = as + ab * (1 - as),
	 * Co(result) = co / ao
	 * when ab = 0, the result is   ( Cs );
	 *  when 1, the result is ( Cs * as ), this is what we want.
	 */
	de200_rtmx[sel].bld_ctl->bld_pipe_attr[pno].fcolor.dwval =
	    0xff000000 | color;
	de200_rtmx[sel].bld_ctl->bld_pipe_attr[pno].insize.bits.width =
	    bldrc.w == 0 ? 0 : bldrc.w - 1;
	de200_rtmx[sel].bld_ctl->bld_pipe_attr[pno].insize.bits.height =
	    bldrc.h == 0 ? 0 : bldrc.h - 1;
	de200_rtmx[sel].bld_ctl->bld_pipe_attr[pno].offset.bits.coorx = bldrc.x;
	de200_rtmx[sel].bld_ctl->bld_pipe_attr[pno].offset.bits.coory = bldrc.y;

	bld_attr_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_set_route(unsigned int sel, unsigned char pno, unsigned int zoder)
{
	unsigned int route;

	route =
	    de200_rtmx[sel].bld_ctl->bld_route_ctl.dwval
	    & (~(0xf << (pno << 2)));
	__inf("sel%d, pno%d, zorder%d, route:0x%x\n", sel, pno, zoder, route);
	de200_rtmx[sel].bld_ctl->bld_route_ctl.dwval =
	    route | (zoder << (pno << 2));
	__inf("addr=0x%p, reg=0x%x\n", &de200_rtmx[sel].bld_ctl->bld_route_ctl,
	      de200_rtmx[sel].bld_ctl->bld_route_ctl.dwval);

	bld_ctl_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_set_premul(unsigned int sel, unsigned char pno,
		       unsigned int pre_mul)
{
	unsigned int pre_mode;

	pre_mode =
	    de200_rtmx[sel].bld_ctl->bld_premultiply_ctl.dwval
	    & (~(0x1 << pno));
	de200_rtmx[sel].bld_ctl->bld_premultiply_ctl.dwval =
	    pre_mode | (pre_mul << pno);

	bld_ctl_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_set_background_color(unsigned int sel, unsigned int color)
{

	de200_rtmx[sel].bld_ctl->bld_bkcolor.dwval =
	    (0xff << 24) | (color & 0xffffff);

	bld_ctl_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_set_blend_size(unsigned int sel, unsigned int w, unsigned int h)
{
	de200_rtmx[sel].bld_ctl->bld_output_size.bits.width =
	    w == 0 ? 0 : w - 1;
	de200_rtmx[sel].bld_ctl->bld_output_size.bits.height =
	    h == 0 ? 0 : h - 1;

	bld_ctl_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_set_blend_mode(unsigned int sel, unsigned int bldno,
			   unsigned char mode)
{
	unsigned int bld_mode;

	if (DE_BLD_CLEAR == mode)
		bld_mode = 0x00000000;
	else if (DE_BLD_SRC == mode)
		bld_mode = 0x00010001;
	else if (DE_BLD_DST == mode)
		bld_mode = 0x01000100;
	else if (DE_BLD_SRCOVER == mode)
		bld_mode = 0x03010301;
	else if (DE_BLD_DSTOVER == mode)
		bld_mode = 0x01030103;
	else if (DE_BLD_SRCIN == mode)
		bld_mode = 0x00020002;
	else if (DE_BLD_DSTIN == mode)
		bld_mode = 0x02000200;
	else if (DE_BLD_SRCOUT == mode)
		bld_mode = 0x00030003;
	else if (DE_BLD_DSTOUT == mode)
		bld_mode = 0x03000300;
	else if (DE_BLD_SRCATOP == mode)
		bld_mode = 0x03020302;
	else if (DE_BLD_DSTATOP == mode)
		bld_mode = 0x02030203;
	else if (DE_BLD_XOR == mode)
		bld_mode = 0x03030303;
	else
		bld_mode = 0x03010301;

	de200_rtmx[sel].bld_ctl->bld_mode[bldno].dwval = bld_mode;

	bld_ctl_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_set_blend_color(unsigned int sel, unsigned int bldno,
			    unsigned int color)
{
	de200_rtmx[sel].bld_ctl->bld_pipe_attr[bldno].fcolor.dwval =
	    (0xff << 24) | (color & 0xffffff);
	bld_attr_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_set_outitl(unsigned int sel, unsigned char interlace_en)
{

	de200_rtmx[sel].bld_ctl->bld_out_ctl.bits.interlace_en =
	    interlace_en & 0x1;
	de200_rtmx[sel].bld_ctl->bld_out_ctl.bits.premultiply_en = 0x0;

	bld_out_block[sel].dirty = 1;

	return 0;
}

int de_rtmx_set_colorkey(unsigned int sel, unsigned char ck_no,
			 unsigned char ck_mode, unsigned char ck_red_match,
			 unsigned char ck_green_match,
			 unsigned char ck_blue_match, unsigned int ck_max,
			 unsigned int ck_min)
{
	unsigned int tmp, ck_match;

	tmp =
	    de200_rtmx[sel].bld_ctl->bld_ck_ctl.
	    dwval & (~(0x6 << (0x2 << ck_no)));
	de200_rtmx[sel].bld_ctl->bld_ck_ctl.dwval =
	    tmp | (ck_mode << (0x2 << (ck_no + 0x1)));

	ck_match = (ck_red_match << 2) | (ck_green_match << 1) | ck_blue_match;
	tmp =
	    de200_rtmx[sel].bld_ctl->bld_ck_cfg.
	    dwval & (~(0x7 << (ck_no << 8)));
	de200_rtmx[sel].bld_ctl->bld_ck_ctl.dwval =
	    tmp | (ck_match << (ck_no << 8));

	de200_rtmx[sel].bld_ctl->bld_ck_max[ck_no].dwval = ck_max & 0xffffff;
	de200_rtmx[sel].bld_ctl->bld_ck_min[ck_no].dwval = ck_min & 0xffffff;

	bld_ck_block[sel].dirty = 1;

	return 0;
}

struct de_rect de_rtmx_extend_rect(struct de_rect rc1, struct de_rect rc2)
{
	struct de_rect rc;
	int xmax, ymax;

	if ((0 == rc1.w) || (0 == rc1.h))
		return rc2;
	rc.x = min2(rc1.x, rc2.x);
	rc.y = min2(rc1.y, rc2.y);

	xmax = max2(rc1.x + rc1.w, rc2.x + rc2.w);
	ymax = max2(rc1.y + rc1.h, rc2.y + rc2.h);

	rc.w = xmax - rc.x;
	rc.h = ymax - rc.y;

	return rc;
}

int de_rtmx_calc_chnrect(unsigned char *lay_en, int laynum,
	struct de_rect *frame, struct de_rect *crop, int gsu_sel,
	struct scaler_para *step, struct de_rect *layer,
	struct de_rect *bld_rect, unsigned int *ovlw, unsigned int *ovlh)
{
	unsigned int i, minx, miny, pipe_en;
	struct de_rect RCOVL = { 0, 0, 0, 0 };
	struct de_rect RCBLD = { 0, 0, 0, 0 };

	minx = 0xffffffff;
	miny = 0xffffffff;

	/* find min cord */
	for (i = 0; i < laynum; i++) {
		if (lay_en[i]) {
			minx = min2(frame[i].x, minx);
			miny = min2(frame[i].y, miny);
		}
	}

	/* recall the layer cord by sub */
	for (i = 0; i < laynum; i++) {
		if (lay_en[i]) {
			layer[i].x =
			    de_calc_ovl_coord(frame[i].x - minx, step[i].hstep,
				      gsu_sel);
			layer[i].y =
			    de_calc_ovl_coord(frame[i].y - miny, step[i].vstep,
				      gsu_sel);
			layer[i].w = crop[i].w;
			layer[i].h = crop[i].h;
			__inf("layernum=%d, i=%d\n", laynum, i);
			__inf("crop=<%d,%d,%d,%d>\n", crop[i].x, crop[i].y,
			      crop[i].w, crop[i].h);
			__inf("layer=<%d,%d,%d,%d>\n", layer[i].x, layer[i].y,
			      layer[i].w, layer[i].h);
		}
	}

	for (i = 0; i < laynum; i++) {
		if (lay_en[i]) {
			RCOVL = de_rtmx_extend_rect(RCOVL, layer[i]);
			RCBLD = de_rtmx_extend_rect(RCBLD, frame[i]);
			__inf("ovl_rect=<%d,%d,%d,%d>\n", RCOVL.x, RCOVL.y,
			      RCOVL.w, RCOVL.h);
			__inf("bld_rect=<%d,%d,%d,%d>\n", RCBLD.x, RCBLD.y,
			      RCBLD.w, RCBLD.h);
		}
	}

	*ovlw = RCOVL.w;
	*ovlh = RCOVL.h;

	bld_rect->x = RCBLD.x;
	bld_rect->y = RCBLD.y;
	bld_rect->w = RCBLD.w;
	bld_rect->h = RCBLD.h;

	pipe_en = 1;
	if ((0 == RCBLD.w) || (0 == RCBLD.h))
		pipe_en = 0;

	return pipe_en;
}

/* ycbcr odd/even */
int de_rtmx_trimcoord(struct de_rect *frame, struct de_rect *crop,
		unsigned int outw, unsigned int outh, int xratio, int yratio)
{
	int left, right, up, down;
	int cut_up, cut_down, cut_left, cut_right;
	int hstep, vstep;/* hphase, vphase;*/

	if ((frame->w == 0) || (frame->h == 0)) {
		hstep = vstep = 0;
		/* hphase = vphase = 0; */
		xratio = hstep;
		yratio = vstep;

		return 0;
	}
	/* calculate scaler step size */
	hstep = (crop->w << 18) / frame->w;
	vstep = (crop->h << 18) / frame->h;

	/* calculate scaling ratio */
	xratio = hstep;
	yratio = vstep;

	/* assume only frame coordinate has negative value */
	left = up = 0;
	cut_left = cut_right = cut_up = cut_down = 0;
	if (((frame->x + (int)frame->w) < 0) || ((frame->x - outw) > 0)) {
		/* out of screen */
		frame->w = frame->x = 0;
	} else if (frame->x < 0) {
		/* cut left */
		left = (((-frame->x) * crop->w) << 18) / frame->w;
		cut_left = (int)(left >> 18);

		frame->w += frame->x;
		frame->x = 0;
	} else if ((frame->x + frame->w) > outw) {
		/* cut right */
		right =
		    (((frame->x + frame->w - outw) * crop->h) << 18) / frame->h;
		cut_right = (int)(right >> 18);

		frame->w = outw - frame->x;
	}
	crop->x += cut_left;
	crop->w -= (cut_left + cut_right);
	/* hphase = (int)(left & 0x3ffff); */

	if (((frame->y + (int)frame->h) < 0) || ((frame->y - outh) > 0)) {
		/* out of screen */
		frame->h = frame->y = 0;
	} else if (frame->y < 0) {
		/* cut up */
		up = (((-frame->y) * crop->h) << 18) / frame->h;
		cut_up = (int)(up >> 18);

		frame->h += frame->y;
		frame->y = 0;
	} else if ((frame->y + frame->h) > outh) {
		/* cut down */
		down =
		    (((frame->y + frame->h - outh) * crop->h) << 18) / frame->h;
		cut_down = (int)(down >> 18);

		frame->h = outh - frame->y;
	}
	crop->y += cut_up;
	crop->h -= (cut_up + cut_down);
	/* vphase = (int)(up & 0x3ffff); */

	return 0;
}

int de_rtmx_get_premul_ctl(int laynum, unsigned char *premul)
{
	int i, same, pipe_mode;

	same = 0;
	pipe_mode = 1;
	for (i = 0; i < laynum; i++)
		same += premul[i];

	for (i = 0; i < laynum; i++) {
		if (premul[i]) {
			premul[i] = 2;
		} else if (0 == same)
			/* all zero */
		{
			pipe_mode = 0;
			premul[i] = 0;
		} else {
			premul[i] = 1;
		}
	}

	return pipe_mode;
}

int de_rtmx_mux(unsigned int sel, unsigned int tcon_index)
{
	u32 reg_val;
	if (sel == tcon_index) {
		reg_val = readl((void __iomem *)(de_base + 0x10));
		reg_val &= ~0x1;
		writel(reg_val, (void __iomem *)(de_base + 0x10));
	} else {
		reg_val = readl((void __iomem *)(de_base + 0x10));
		reg_val |= 0x1;
		writel(reg_val, (void __iomem *)(de_base + 0x10));
	}

	return 0;
}

int de_rtmx_get_mux(unsigned int sel)
{
	u32 reg_val;
	reg_val = readl((void __iomem *)(de_base + 0x10));
	reg_val &= 0x1;

	return (reg_val == 0) ? (sel) : (1 - sel);
}

int de_rtmx_sync_hw(unsigned int sel)
{
	int i, j, ui_chno, vi_chno, layno;

	vi_chno = de_feat_get_num_vi_chns(sel);
	ui_chno = de_feat_get_num_ui_chns(sel);
	layno = LAYER_MAX_NUM_PER_CHN;

	memcpy(glb_ctl_block[sel].val, (void *)glb_ctl_block[sel].off,
	       glb_ctl_block[sel].size);

	for (j = 0; j < vi_chno; j++) {
		for (i = 0; i < layno; i++) {
			memcpy(vi_attr_block[sel][j][i].val,
			       (void *)vi_attr_block[sel][j][i].off,
			       vi_attr_block[sel][j][i].size);
		}

		memcpy(vi_fc_block[sel][j].val,
		    (void *)vi_fc_block[sel][j].off,
		    vi_fc_block[sel][j].size);

		memcpy(vi_haddr_block[sel][j].val,
		    (void *)vi_haddr_block[sel][j].off,
		    vi_haddr_block[sel][j].size);

		memcpy(vi_size_block[sel][j].val,
		    (void *)vi_size_block[sel][j].off,
		    vi_size_block[sel][j].size);
	}

	for (j = 0; j < ui_chno; j++) {
		for (i = 0; i < layno; i++) {
			memcpy(ui_attr_block[sel][j][i].val,
			    (void *)ui_attr_block[sel][j][i].off,
			    ui_attr_block[sel][j][i].size);
		}

		memcpy(ui_haddr_block[sel][j].val,
		    (void *)ui_haddr_block[sel][j].off,
		    ui_haddr_block[sel][j].size);

		memcpy(ui_size_block[sel][j].val,
		    (void *)ui_size_block[sel][j].off,
		    ui_size_block[sel][j].size);
	}

	memcpy(bld_attr_block[sel].val,
	    (void *)bld_attr_block[sel].off,
	    bld_attr_block[sel].size);

	memcpy(bld_ctl_block[sel].val,
	    (void *)bld_ctl_block[sel].off,
	    bld_ctl_block[sel].size);

	memcpy(bld_ck_block[sel].val,
	    (void *)bld_ck_block[sel].off,
	    bld_ck_block[sel].size);

	memcpy(bld_out_block[sel].val,
	    (void *)bld_out_block[sel].off,
	    bld_out_block[sel].size);

	return 0;
}

int de_rtmx_get_lay_enabled(unsigned int sel, unsigned int chno,
			    unsigned int layno)
{
	int vi_chno = de_feat_get_num_vi_chns(sel);
	int ret = 0;

	if (chno >= vi_chno) {
		ret =
		    de200_rtmx[sel].ui_ovl[chno - vi_chno]
		    ->ui_lay_cfg[layno].lay_attr.bits.lay_en;
	} else {
		ret =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno]
		    .lay_attr.bits.lay_en;
	}

	return ret;
}

int de_rtmx_get_lay_address(unsigned int sel, unsigned int chno,
			    unsigned int layno, unsigned long long *addr)
{
	int vi_chno = de_feat_get_num_vi_chns(sel);
	int ret = 0;
	unsigned long long tmp;

	if (chno >= vi_chno) {
		addr[0] = de200_rtmx[sel].ui_ovl[chno - vi_chno]->
		ui_lay_cfg[layno].lay_top_laddr.dwval;
		/* low address */
		tmp = de200_rtmx[sel].ui_ovl[chno - vi_chno]
		->ui_lay_top_haddr.dwval & (0xff << layno);
		/* high address */
		addr[0] |= tmp << 32;
		addr[1] = 0;
		addr[2] = 0;
	} else {
		addr[0] =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_top_laddr[0].dwval;
		addr[1] =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_top_laddr[1].dwval;
		addr[2] =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_top_laddr[2].dwval;

		tmp = de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[0].dwval
		& (0xff << layno);
		/* high address */
		addr[0] |= tmp << 32;
		tmp =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[1].dwval
		    & (0xff << layno);
		addr[1] |= tmp << 32;
		tmp =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_top_haddr[2].dwval
		    & (0xff << layno);
		addr[2] |= tmp << 32;
	}

	return ret;
}

int de_rtmx_get_lay_size(unsigned int sel, unsigned int chno,
			 unsigned int layno, struct disp_rectsz *size)
{
	int vi_chno = de_feat_get_num_vi_chns(sel);
	int ret = 0;
	int fmt, ycnt = 4, ucnt = 2;

	if (chno >= vi_chno) {
		fmt =
		    de200_rtmx[sel].ui_ovl[chno -
					   vi_chno]->ui_lay_cfg[layno].lay_attr.
		    bits.lay_fmt;
		if (fmt <= DE_FORMAT_BGRX_8888)
			ycnt = 4;
		else if (fmt <= DE_FORMAT_BGR_888)
			ycnt = 3;
		else if (fmt <= DE_FORMAT_BGRA_5551)
			ycnt = 2;
		else
			ycnt = 4;

		size[0].width = de200_rtmx[sel].ui_ovl[chno - vi_chno]->
		ui_lay_cfg[layno].lay_pitch.dwval / ycnt;
		/* fixme,according to format */
		size[0].height =
		    de200_rtmx[sel].ui_ovl[chno - vi_chno]
		    ->ui_lay_cfg[layno].lay_size.bits.lay_height;
	} else {
		fmt =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.
		    bits.lay_fmt;
		if (fmt <= DE_FORMAT_BGRX_8888) {
			ycnt = 4;
		} else if (fmt <= DE_FORMAT_BGR_888) {
			ycnt = 3;
		} else if (fmt <= DE_FORMAT_BGRA_5551) {
			ycnt = 2;
		} else if (fmt <= DE_FORMAT_YUV422_I_VYUY) {
			ycnt = 2;
		} else if (fmt == DE_FORMAT_YUV422_P) {
			ycnt = 1;
			ucnt = 1;
		}
		/* YUV422 */
		else if (fmt == DE_FORMAT_YUV420_P) {
			ycnt = 1;
			ucnt = 1;
		}
		/* YUV420 */
		else if (fmt == DE_FORMAT_YUV411_P) {
			ycnt = 1;
			ucnt = 1;
		}
		/* YUV411 */
		else if (fmt <= DE_FORMAT_YUV422_SP_VUVU) {
			ycnt = 1;
			ucnt = 2;
		} else if (fmt <= DE_FORMAT_YUV420_SP_VUVU) {
			ycnt = 1;
			ucnt = 2;
		} else if (fmt <= DE_FORMAT_YUV411_SP_VUVU) {
			ycnt = 1;
			ucnt = 2;
		} else {
			ycnt = 4;
		}
		size[0].width =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_pitch[0].dwval / ycnt;
		size[1].width =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_pitch[1].dwval / ucnt;
		size[2].width =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].
		    lay_pitch[2].dwval / ucnt;
		size[0].height =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_size.
		    bits.lay_height;
		size[2].height = size[1].height = size[0].height;
	}

	return ret;
}

int de_rtmx_get_lay_win(unsigned int sel, unsigned int chno, unsigned int layno,
			struct disp_rect *win)
{
	int vi_chno = de_feat_get_num_vi_chns(sel);
	int ret = 0;

	if (chno >= vi_chno) {
		win->width =
		    de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].
		    lay_size.bits.lay_width + 1;
		win->height =
		    de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].
		    lay_size.bits.lay_height + 1;
	} else {
		win->width =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_size.
		    bits.lay_width + 1;
		win->height =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_size.
		    bits.lay_height + 1;
	}

	return ret;
}

int de_rtmx_get_display_size(unsigned int sel, unsigned int *width,
			     unsigned int *height)
{
	*width = de200_rtmx[sel].glb_ctl->glb_size.bits.width + 1;
	*height = de200_rtmx[sel].glb_ctl->glb_size.bits.height + 1;

	return 0;
}

int de_rtmx_get_lay_format(unsigned int sel, unsigned int chno,
			   unsigned int layno)
{
	int vi_chno = de_feat_get_num_vi_chns(sel);
	int fmt = 0;

	if (chno >= vi_chno) {
		fmt =
		    de200_rtmx[sel].ui_ovl[chno - vi_chno]->ui_lay_cfg[layno].
		    lay_attr.bits.lay_fmt;
	} else {
		fmt =
		    de200_rtmx[sel].vi_ovl[chno]->vi_lay_cfg[layno].lay_attr.
		    bits.lay_fmt;

		if (fmt == 0)
			fmt = DE_FORMAT_YUV422_I_VYUY;
		else if (fmt == 1)
			fmt = DE_FORMAT_YUV422_I_YVYU;
		else if (fmt == 2)
			fmt = DE_FORMAT_YUV422_I_UYVY;
		else if (fmt == 3)
			fmt = DE_FORMAT_YUV422_I_YUYV;
		else if (fmt == 4)
			fmt = DE_FORMAT_YUV422_SP_UVUV;
		else if (fmt == 5)
			fmt = DE_FORMAT_YUV422_SP_VUVU;
		else if (fmt == 6)
			fmt = DE_FORMAT_YUV422_P;
		else if (fmt == 8)
			fmt = DE_FORMAT_YUV420_SP_UVUV;
		else if (fmt == 9)
			fmt = DE_FORMAT_YUV420_SP_VUVU;
		else if (fmt == 0xa)
			fmt = DE_FORMAT_YUV420_P;
		else if (fmt == 0xc)
			fmt = DE_FORMAT_YUV411_SP_UVUV;
		else if (fmt == 0xd)
			fmt = DE_FORMAT_YUV411_SP_VUVU;
		else if (fmt == 0xe)
			fmt = DE_FORMAT_YUV411_P;
	}

	return fmt;
}
